package com.gxa.zuul.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gxa.zuul.service.YongHuService;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author thinknovo
 * @version 1.0
 * @description MyFormAuthenticationFilter.java
 */
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
    @Resource
    private YongHuService userServiceImpl;

    public MyFormAuthenticationFilter() {
        System.out.println("----------------MyFormAuthenticationFilter-------构造函数-----------");
    }

    /**
     * 这个方法决定了是否需要用户登录
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        // Remembered=false  Authenticated=false，代表用户没有登录，也没有缓存
        // Remembered=true  Authenticated=false，代表用户没有登录，但是有缓存
        // Remembered=false  Authenticated=true，代表用户当前登录成功，缓存有，但是在当前登录页面时不会记录
        // Remembered=true  Authenticated=true， 不会出现
        Subject subject = getSubject(request, response);
        System.out.println("MyFormAuthenticationFilter  -------------------------  isAccessAllowed isRemembered=" + subject.isRemembered());
        System.out.println("MyFormAuthenticationFilter  -------------------------  isAccessAllowed isAuthenticated=" + subject.isAuthenticated());
        /*
        如果isAuthenticated 为 true 代表用户手动输入用户名和密码登录
        如果isRemembered 为 true 代表用户直接通过RemenberMe功能登录
        按照官方说明isAuthenticated和isRememberd是互斥的，即任中一个为true，另外一个必为false
        如果希望在用户两种情况添加额外处理，可以写在下面if else中
         */
        if(subject.isAuthenticated()) {  // 登录状态  true   false true   false
            System.out.println("subject.isAuthenticated()=" + subject.isAuthenticated());
            // do work...
        }
        else if(subject.isRemembered()) {  // cookie缓存状态  false true    true  false
            System.out.println("subject.isRemembered()=" + subject.isRemembered());
            // do work...
        }
        //这个方法默认只返回 subject.isAuthenticated()   加上 subject.isRemembered() 目的是让它同时也兼容remember这种情况
        return subject.isAuthenticated() || subject.isRemembered();
    }

    /**
     * 此方法的作用在于前后分离时项目管理。
     * 在前后分离开发中，当验证登录失败时，会使用onAccessDenied返回登录失败的json信息
     * @param request    请求对象
     * @param response   响应对象
     * @return            返回状态(true放行，false拦截)
     * @throws Exception  异常
     */
    @Override
    public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("-----MyFormAuthenticationFilter------onAccessDenied-------------");
//        if (isLoginRequest(request, response)) {
//            if (isLoginSubmission(request, response)) {
//                if (log.isTraceEnabled()) {
//                    log.trace("Login submission detected.  Attempting to execute login.");
//                }
//                return executeLogin(request, response);
//            } else {
//                if (log.isTraceEnabled()) {
//                    log.trace("Login page view.");
//                }
//                return true;
//            }
//        } else {
//            HttpServletRequest httpRequest = WebUtils.toHttp(request);
//
//            if (checkAjax(httpRequest)) {
//                HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
//                httpServletResponse.sendError(401);
//                return false;
//            } else {
//                if (log.isTraceEnabled()) {
//                    log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
//                            "Authentication url [" + getLoginUrl() + "]");
//                }
//                saveRequestAndRedirectToLogin(request, response);
//            }
//
//            return false;
//        }

        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setStatus(200);
        httpServletResponse.setContentType("application/json;charset=utf-8");

        PrintWriter out = httpServletResponse.getWriter();
        ObjectMapper json = new ObjectMapper();
        Map<String, Object> map = new HashMap<>();
        map.put("code",10500);
        map.put("msg","未检查到登录状态或者权限不满足，请重新登录或授权！");
        System.out.println(map);
        out.print(json.writeValueAsString(map));
        out.flush();
        out.close();
        return false;
    }

    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        System.out.println("---------redirectToLogin----------");
        super.redirectToLogin(request, response);
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setStatus(200);
        httpServletResponse.setContentType("application/json;charset=utf-8");

        PrintWriter out = httpServletResponse.getWriter();
        ObjectMapper json = new ObjectMapper();
        Map<String, Object> map = new HashMap<>();
        map.put("code",10500);
        map.put("msg","未检测到授权！");
        System.out.println(map);
        out.print(json.writeValueAsString(map));
        out.flush();
        out.close();
    }

    @Bean
    public FilterRegistrationBean registration(MyFormAuthenticationFilter myFormAuthenticationFilter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(myFormAuthenticationFilter);
        registration.setEnabled(false);
        return registration;
    }

    /*
     * 判断ajax请求 ajax请求的头文件包含X-Requested-With
     * @param request
     * @return
     */
    boolean checkAjax(HttpServletRequest request){
        return  (request.getHeader("X-Requested-With") != null  && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString())   ) ;
    }


}
